import { Component, OnInit, Inject, OnDestroy } from "@angular/core";
import { AddressComponent } from "../address/address.component";

import {
  LocaleService,
  TranslationService,
  Language,
  DefaultLocale
} from "angular-l10n";

import { Store, select } from "@ngrx/store";
import * as fromUser from "@/user/store/reducers/index";
import * as fromTrade from "@/trade/store/reducers/index";
import * as fromAssets from "@/assets/store/reducers/index";
import * as fromRoot from "@/reducers/index";
import { map, filter, skip } from "rxjs/operators";
import { Subscription } from "rxjs";
import { AssetsActions } from "@/assets/store/actions";
import {
  AsyncValidator,
  NG_ASYNC_VALIDATORS,
  ValidationErrors,
  AbstractControl,
  FormBuilder,
  FormGroup,
  Validators,
  ControlValueAccessor,
  NG_VALUE_ACCESSOR,
  FormControl
} from "@angular/forms";
import { forkJoin, combineLatest, zip } from "rxjs";
import { combineAll, debounceTime } from "rxjs/operators";
import { Router, NavigationEnd } from "@angular/router";
import { ActivatedRoute } from "@angular/router";
import { ISelectAssetsRequest } from "@/assets/store/models/assets";

import {
  IFindAssetsResponseData,
  IAddressListsItem,
  IWithdrawRequest,
  ISelectWithdrawAddressRequest
} from "@/assets/store/models/assets";

import createNumberMask from "text-mask-addons/dist/createNumberMask.js";

import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from "@angular/material";

interface IAddressItem {
  coin: string;
  address: string;
  remark: string;
}

@Component({
  selector: "app-withdraw",
  templateUrl: "./withdraw.component.html",
  styleUrls: ["./withdraw.component.scss"]
})
export class WithdrawComponent implements OnInit, OnDestroy {
  validateForm: FormGroup;

  @Language() lang: string;

  search: FormControl = new FormControl("");

  dialogRef: MatDialogRef<AddressComponent>;

  assets$ = this.store
    .pipe(select(fromRoot.assets))
    .pipe(filter(assets => !!assets));

  assets: IFindAssetsResponseData = {
    coin: "",
    total: "",
    ava: "",
    frozen: "",
    point: 0,
    feeRatio: "",
    baseFee: "",
    withdraw: {
      min: "",
      max: ""
    },
    deposit: {
      min: "",
      confirm: ""
    }
  };

  user$ = this.store.pipe(
    select(fromRoot.user),
    filter(user => !!user)
  );

  withdrawAddressLists$ = this.store
    .pipe(select(fromRoot.withdrawAddressLists))
    .pipe(filter(withdrawAddressLists => !!withdrawAddressLists));

  public pointMask: any;

  req: IWithdrawRequest = {
    amount: "",
    coin: "",
    address: "",
    uid: ""
  };

  sub$ = {
    addressListsSub$: null,
    withdrawAddressListsSub$: null,
    coinSub$: null,
    assetsSub$: null,
    amountSub$: null,
    formSub$: null,
    userAndQuerySub$: null,
    querySub$: null
  };

  withdrawAddressLists: Array<IAddressListsItem> = [];

  selectWithdrawAddressReq: ISelectWithdrawAddressRequest = {
    uid: "",
    coin: ""
  };

  query = {
    coin: ""
  };

  constructor(
    private fb: FormBuilder,
    @Inject("MsgService") private msgService,
    @Inject("UtilsService") private utilsService,
    @Inject("ConfigService") private configService,
    private store: Store<fromAssets.State | fromUser.State | fromRoot.State>,
    private router: Router,
    public dialog: MatDialog,
    @Inject("DialogService") private dialogService,
    private activatedRoute: ActivatedRoute
  ) {}

  ngOnInit() {
    this.initForm();
    this.addListen();
    // here will change to modal
    // this.msgService.warning(
    //   "Your withdraw limit is low. Please complete KYC authentication to increase your withdrawal limit"
    // );
  }

  initForm() {
    this.validateForm = this.fb.group({
      coin: [null, Validators.required],
      amount: [null, [Validators.required, this.isZero, this.isLimit]],
      // payPwd: [null, Validators.required],
      address: [null, Validators.required],
      total: ["0.00000000"],
      ava: ["0.00000000"],
      frozen: ["0.00000000"],
      passFee: [null],
      receiveAmount: [null]
    });
  }

  isZero = (control: FormControl): { [s: string]: boolean } => {
    if (control.value && Number(control.value.replace(/_/, 0)) === 0) {
      return { zero: true, error: true };
    }
  };

  isLimit = (control: FormControl): { [s: string]: boolean } => {
    if (
      control.value &&
      Number(control.value.replace(/_/, 0)) < Number(this.assets.withdraw.min)
    ) {
      return { limit: true, error: true };
    }
    if (
      control.value &&
      Number(control.value.replace(/_/, 0)) > Number(this.assets.withdraw.max)
    ) {
      return { limit: true, error: true };
    }
  };

  get point() {
    return Number(this.assets.point);
  }

  get fee() {
    const point = this.point;
    const amount = Number(
      this.validateForm.controls.amount.value.replace(/_/, 0)
    );
    const feeRatio = Number(this.assets.feeRatio);
    const baseFee = Number(this.assets.baseFee);
    if (amount === 0) {
      return Number(0).toFixed(point);
    }
    // 2.0638737999999996
    return Number(amount * feeRatio + baseFee);
  }
  onDelAddress(e, item) {
    e.stopPropagation();
    this.dialogService
      .confirm("confirm.del")
      .afterClosed()
      .subscribe(b => {
        if (!b) {
          return;
        }
        this.store.dispatch(
          new AssetsActions.DelAddress({ req: { id: item.id }, cpt: this })
        );
      });
  }

  addListen() {
    this.sub$.userAndQuerySub$ = combineLatest(
      this.user$,
      this.activatedRoute.queryParams
    ).subscribe(([user, query]) => {
      const { coin } = query;
      if (!!coin) {
        const findAssets = new AssetsActions.FindAssets({
          req: {
            coin,
            uid: user.id
          }
        });
        this.store.dispatch(findAssets);
      }
    });

    this.sub$.coinSub$ = this.validateForm.controls.coin.valueChanges.subscribe(
      e => {
        this.router.navigate(["assets/withdraw"], {
          queryParams: {
            coin: e
          }
        });
      }
    );

    this.user$.subscribe(e => {
      // this.req.uid = e.id;
    });

    this.sub$.amountSub$ = this.validateForm.controls.amount.valueChanges.subscribe(
      e => {
        if (!!e) {
          const amount = Number(e.replace(/_/, 0));
          const fee = Number(this.fee);
          const point = this.point;
          const ret = Number(amount - fee);
          this.validateForm.controls.passFee.setValue(fee);
          this.validateForm.controls.receiveAmount.setValue(ret);
        }
      }
    );

    this.sub$.formSub$ = this.validateForm.valueChanges.subscribe(e => {
      this.req.coin = e.coin;
      this.req.address = e.address;
      this.req.amount = e.amount;
    });

    this.sub$.assetsSub$ = this.assets$.subscribe(e => {
      this.assets = e;
      // limit decimal
      this.pointMask = {
        mask: createNumberMask({
          prefix: "",
          suffix: "",
          includeThousandsSeparator: false,
          allowDecimal: true,
          requireDecimal: true,
          decimalLimit: e.point || this.configService.point,
          decimalSymbol: "."
        })
      };
      this.validateForm.controls.ava.setValue(e.ava);
      this.validateForm.controls.total.setValue(e.total);
      this.validateForm.controls.frozen.setValue(e.frozen);
    });

    this.sub$.withdrawAddressListsSub$ = this.withdrawAddressLists$.subscribe(
      withdrawAddressLists => {
        this.withdrawAddressLists = withdrawAddressLists;
      }
    );

    this.sub$.querySub$ = this.activatedRoute.queryParams.subscribe(query => {
      const { coin } = query;
      this.query.coin = coin;

      this.validateForm.controls.coin.setValue(coin);
    });

    this.sub$.addressListsSub$ = combineLatest(
      this.user$,
      this.activatedRoute.queryParams
    ).subscribe(([user, query]) => {
      const { coin } = query;
      if (!!coin) {
        this.selectWithdrawAddressReq = {
          coin,
          uid: user.id
        };
        this.initWithdrawAddressLists();
      }
    });
  }

  // markAsDirty

  onBlurAddress() {
    this.validateForm.controls.address.markAsDirty();
  }

  onBlurAmount() {
    this.validateForm.controls.amount.markAsDirty();
  }

  onBlurPayPwd() {
    // this.validateForm.controls.payPwd.markAsDirty();
  }

  onChangeCoin(e) {
    if (e.coin !== this.query.coin) {
      this.router.navigate(["/assets/withdraw"], {
        queryParams: {
          coin: e.coin
        }
      });
    }
  }
  onSubmit() {
    const withdraw = new AssetsActions.Withdraw({
      req: {
        ...this.req
      },
      cpt: this
    });
    this.store.dispatch(withdraw);
  }

  initWithdrawAddressLists() {
    this.store.dispatch(
      new AssetsActions.SelectWithdrawAddress({
        req: this.selectWithdrawAddressReq,
        cpt: this
      })
    );
  }

  onClickAddress() {
    if (this.withdrawAddressLists.length === 0) {
      this.toAddress();
    }
  }

  toAddress() {
    // this.router.navigate(["assets/address"], {
    //   queryParams: {
    //     coin: this.validateForm.controls.coin.value
    //   }
    // });
    const timer = setTimeout(() => {
      this.dialogRef = this.dialog.open(AddressComponent, {
        width: "420px",
        panelClass: "app-full-bleed-dialog",
        data: { coin: this.validateForm.controls.coin.value }
      });

      this.dialogRef.afterClosed().subscribe(result => {
        console.log("The dialog was closed");
      });
      clearTimeout(timer);
    }, 0);
  }

  ngOnDestroy() {
    this.utilsService.unsub(this.sub$);
  }
}
